package org.ccay.security.web;

import java.io.IOException;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.ccay.core.util.JsonUtil;
import org.ccay.core.util.MimeTypeUtil;
import org.ccay.security.authc.UserInfoPasswordToken;
import org.ccay.security.config.CurrentDimensionConfig;
import org.ccay.security.config.SecurityConfig;
import org.ccay.security.entity.User;
import org.ccay.security.exception.IFriendlyException;
import org.ccay.security.i18n.SecurityI18nUtil;
import org.ccay.security.vo.LoginVO;

public class DimensionFormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
	
	private static final ThreadLocal<String> currentLanguage = new ThreadLocal<String>();
	
	
	protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        String username = getUsername(request);
        String password = getPassword(request);
        User user = new User();
        user.setName(username);
        user.setCurrentDimensions(getCurrentDimension(request, response));
        boolean rememberMe = isRememberMe(request);
        String host = getHost(request);
        return new UserInfoPasswordToken(user, password, rememberMe, host);
    }
    

	protected Map<String,Serializable> getCurrentDimension(ServletRequest request, ServletResponse response){
		Map<String,Serializable> currentDimensions = new HashMap<String,Serializable>();
		for(CurrentDimensionConfig dc : SecurityConfig.getCurrentDimensionConfigs()){
			currentDimensions.put(dc.getDimensionName(), findCurrentDimensionValue(dc,request,response));
		}
    	return currentDimensions;
    }

	/**
	 * 查找当前维度值，如果找不到，返回默认值
	 * 当前维度值通过request.getParameter()--> request.getHeader()-->request.getCookies()
	 * @param dc
	 * @param request
	 * @param response
	 * @return
	 */
	protected Serializable findCurrentDimensionValue(CurrentDimensionConfig dc,
			ServletRequest request, ServletResponse response) {
		String dimensionValue =  request.getParameter(dc.getDimensionParamName());
		//find value from Parameter
		if(null != dimensionValue){
			return typeConvert(dc,dimensionValue);
		}
		if(request instanceof HttpServletRequest){
			HttpServletRequest hsr = WebUtils.toHttp(request);
			//find value from header
			dimensionValue = hsr.getHeader(dc.getDimensionParamName());
			if(null != dimensionValue){
				return typeConvert(dc,dimensionValue);
			}
			//find value from cookies
			for(Cookie cookie : hsr.getCookies()){
				if(cookie.getName().equals(dc.getDimensionParamName())){
					return typeConvert(dc,cookie.getValue());
				}
			}
		}
		return dc.getDefaultCurrentValue();
	}
	
	protected Serializable typeConvert(CurrentDimensionConfig dc,String value){
		Class<?> dimensionType = SecurityConfig.findDimensionDefineConfig(dc.getDimensionName()).getDimensionValueType();
		if(value == null){
			return dc.getDefaultCurrentValue();
		}
		if(dimensionType.equals(String.class)){
			return value;
		}
		if(dimensionType.equals(Long.class)){
			return Long.valueOf(value);
		}
		if(dimensionType.equals(Integer.class)){
			return Integer.valueOf(value);
		}
		if(dimensionType.equals(Boolean.class)){
			return Boolean.valueOf(value);
		}
		throw new IllegalArgumentException("Can not convert value["+value+"] to expect type ["+dimensionType+"]");
	}
    
	
	protected boolean onLoginSuccess(AuthenticationToken token,
			Subject subject, ServletRequest request, ServletResponse response)
			throws Exception {
		
		LoginVO vo = new LoginVO(LoginVO.LOGIN_SUCCESS);
        vo.setRedirectURL(determineSuccessUrl(request));
        response.setContentType(MimeTypeUtil.getTypeBySuffix("json")); 
		JsonUtil.writeJsonToStream(vo, response.getOutputStream());
        //登录处理完成，阻止过滤链继续执行
		return false;
	}

	protected boolean onLoginFailure(AuthenticationToken token,
			AuthenticationException e, ServletRequest request,
			ServletResponse response) {
		setFailureAttribute(request, e);
		LoginVO vo = new LoginVO(LoginVO.LOGIN_FAILURE);
		vo.setErrCode(e.getClass().getName());
		vo.setMessage(e.getMessage());
		if(e instanceof IFriendlyException){
			IFriendlyException fe = ((IFriendlyException) e);
			vo.setErrCode(fe.getErrCode());
			vo.setMessage(MessageFormat.format(SecurityI18nUtil.getI18nMessage(fe.getI18nKey(),request),fe.getArgs()));
			vo.setArgs(fe.getArgs());
		}
        response.setContentType(MimeTypeUtil.getTypeBySuffix("json"));
		try {
			JsonUtil.writeJsonToStream(vo, response.getOutputStream());
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		//登录失败，返回前台出错信息，阻止过滤链继续执行。
		return false;
	}
	
	/**
	 * 计算登录成功后跳转地址
	 * @param token
	 * @param e
	 * @param request
	 * @param response
	 * @return
	 */
	protected String determineSuccessUrl(ServletRequest request) {
		String successUrl = null;
        SavedRequest savedRequest = WebUtils.getAndClearSavedRequest(request);
        if (savedRequest != null && savedRequest.getMethod().equalsIgnoreCase(AccessControlFilter.GET_METHOD)) {
            successUrl = savedRequest.getRequestUrl();
        }
        if (successUrl == null) {
            successUrl = getSuccessUrl();
        }
        return successUrl;
	}
}
